/* 
 * StikiWeb Wiki - a Wiki for Hierarchical Organizations
 * $Id: AdminPageAction.java,v 1.5 2004/05/07 14:58:10 biglee Exp $
 * 
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the StikiWeb Wiki.
 *
 * The Initial Developer of the Original Code is Lee Haslup (biglee@haslups.com).
 * Portions created by the Initial Developer are Copyright (C) 2004
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * ***** END LICENSE BLOCK ***** 
 */
package org.stikiweb.struts;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import org.stikiweb.contentMagnager.PageInfoNode;
import org.stikiweb.contentMagnager.PermissionManager;
import org.stikiweb.translations.StikiWebTranslator;

/**
 * @author Allen L (BigLee) Haslup
 *
 */
public class AdminPageAction extends StikiAction {

	/* (non-Javadoc)
	 * @see org.apache.struts.action.Action#execute(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	public ActionForward execute(
		ActionMapping mapping,
		ActionForm form,
		HttpServletRequest req,
		HttpServletResponse resp)
		throws Exception {
		
		//make sure we are set up and good to go
		setup(req);

		HttpSession session = req.getSession();
		AdminBean ab = (AdminBean) form;
		
		// if we are re-using the same bean for a different page, make sure we don't have
		// any button values hanging around.  
		if(ab.getResetBean()!=null && ab.getResetBean().length()>0) {
			ab.setResetBean("");
			ab.setGoToChild("");
			ab.setGoToParent("");
			ab.setCancel("");
			ab.setApply("");
			ab.setNewUserId("");
			ab.setNewUserPerm("");
			ab.setSave("");
		}

		// if there is no input we don't know what page to edit so we fail.
		if (ab == null || ab.getName() == null) {
			return mapping.findForward("failure");
		}

		PermissionManager pm = PermissionManager.solo();
		// the name "." is a synonym for the current page
		String thePage = ab.getName().trim();
		if(thePage.equals(".")) {
			thePage = (String)session.getAttribute("currentPage");
			if(thePage==null) {
				thePage="";
			}
		}
		// and the name ".." is a synonym for the page with the empty name (the
		// top of the hierarchy)
		else if(thePage.equals("..")) {
			thePage = "";
		}
		thePage = StikiWebTranslator.crushName(thePage);
		ab.setName(thePage);
		String thisAdmin = pm.getUserName(req);
		
		
		// check the user's permission level
		if(pm.userPermLevelForPage(thisAdmin,thePage)<PermissionManager.ADMIN) {
			if(isLoggedIn(req)){
				return mapping.findForward("failure");
			}
			return goLoginFirst("adminPage","",thePage,req);
		}

		// if the user pressed CANCEL, return success to return
		// to the page view.
		if (ab.getCancel() != null && ab.getCancel().length() > 0) {
			ab.reset(mapping,req);
			return new ActionForward("/viewPage.do?name="+thePage,true);
		}

		// note which button the user has pressed
		boolean applying =
			(ab.getApply() != null && ab.getApply().length() > 0);
		boolean saving = 
		   (ab.getSave() != null && ab.getSave().length() > 0)
		|| (ab.getGoToParent() != null && ab.getGoToParent().length()>0)
		|| (ab.getGoToChild() != null && ab.getGoToChild().length()>0);

		// keep a running tally of usersnames for the add user
		// picklist.  We will drop users already on the list and
		// the current user (Administrators can't administer
		// themselves).
		TreeMap otherUsers = pm.userNames();
		otherUsers.put("Visitor","Visitor");
		otherUsers.put("default","default");
		otherUsers.remove(thisAdmin);

		// ====================================
		// Set up userPerms list
		// ====================================
		// INITIAL CALL - set up bean from perm mgr info..
		// if we are neither adding nor saving then populate the
		// user perms section of the bean with information from
		// the permission manager.  First, Pick up max storage and
		// reserved storage and max storage per attachment.
		if (!saving && !applying)  {
			ab.setResetBean("");
			boolean newRecord = false;
			PermissionManager.PageSpec pSpec = pm.getPageSpec(thePage);
			if (pSpec == null) {
				pSpec = pm.new PageSpec();
				newRecord = true;
			}
			ab.setNewRecord(newRecord);
			// max storage (total allocation) coded as *blank* = 0
			if (pSpec.maxStorage>0) {
				ab.setMaxStorage(Integer.toString(pSpec.maxStorage));
			}
			else {
				ab.setMaxStorage("");
			}
			// available storage
			ab.setAvailableStorage(""+PageInfoNode.availableStorage(thePage));
			// storage used
			ab.setStorageUsed(""+PageInfoNode.actualSize(thePage));
			// max size of attachments coded as *blank* = -1
			if(pSpec.maxStoragePerAttach>=0) {
				ab.setMaxSizePerAttachment(
					Integer.toString(pSpec.maxStoragePerAttach));
			}
			else {
				ab.setMaxSizePerAttachment("");
			}
			// reserved storage coded as *empty* = off
			if (pSpec.reservedStorage)
				ab.setReservedStorage("on");
			// template name
			if(pSpec.templateName!=null) {
				ab.setTemplateName(pSpec.templateName);
			}
			else {
				ab.setTemplateName("");
			}
			// build list of users with permissions for page
			ArrayList usersbuf = new ArrayList();
			Iterator it = pSpec.userPermLevel.keySet().iterator();
			while (it.hasNext()) {
				String usrName = (String) it.next();
				UserPermBean upb = new UserPermBean();
				upb.setUser(usrName);
				if(usrName.equals(pm.getUserName(req))) {
					upb.setPerm("ADMIN*");
				}
				else {
					int permLvl = ((Integer) pSpec.userPermLevel.get(usrName)).intValue();
					upb.setPerm(pm.permStringFromLevel(permLvl));
				}
				usersbuf.add(upb);
				// remove this user from the add user picklist
				otherUsers.remove(usrName);
			}
			ab.setUsers(usersbuf);
			// then set the parent page info.
			String pPage = pm.getAdminParent(thePage);
			if(pPage==null) {
				ab.setAdminParent("none");
				ab.setCanAdminParent("");
			}
			else {
				ab.setAdminParent(pPage==""?"..":pPage);
				ab.setCanAdminParent(pm.userPermLevelForPage(thisAdmin,pPage)>=PermissionManager.ADMIN?"Yes":"");
			}
			// set the child page info
			ArrayList childPageNames = pm.getAdminChildren(thePage);
			ArrayList childPages = new ArrayList();
			Iterator iChild = childPageNames.iterator();
			while(iChild.hasNext()) {
				String aChildName = (String)iChild.next();
				PermissionManager.PageSpec childPs = pm.getPageSpec(aChildName);
				if(childPs!=null) {
					AdminChildBean acb = new AdminChildBean();
					acb.setName(aChildName);
					if(childPs.maxStorage>0) {
						acb.setMaxStorage(Integer.toString(childPs.maxStorage));
					}
					else {
						acb.setMaxStorage("");
					} 
					acb.setReservedStorage(childPs.reservedStorage?"Yes":"No");
					if(childPs.maxStoragePerAttach>=0) {
						acb.setMaxSizePerAttachment(Integer.toString(childPs.maxStoragePerAttach));
					}
					else {
						acb.setMaxSizePerAttachment("");
					}
					childPages.add(acb);
				}
			}
			ab.setAdminChildren(childPages);
			ab.setSelectedChild("");
		} 
		else {
			// ================================
			// SUBSEQUENT CALL -- apply user markup to bean
			// we are either saving or adding ... in either event
			// apply marked changes (add/delete user) to the bean.
			// first, pack out deleted entries from user perm list...
			ArrayList newUserPerms = new ArrayList();
			Iterator it = ab.getUsers().iterator();
			UserPermBean upb;
			while (it.hasNext()) {
				upb = (UserPermBean) it.next();
				if (!upb.getPerm().equals("REMOVE")) {
					newUserPerms.add(upb);
					// remove this user from the add users picklist
					otherUsers.remove(upb.getUser());
				}
			}
			// ...and add the new user if one is specified
			if (ab.getNewUserId().length() > 0
				&& ab.getNewUserPerm().length() > 0) {
				upb = new UserPermBean();
				upb.setUser(ab.getNewUserId());
				upb.setPerm(ab.getNewUserPerm());
				newUserPerms.add(upb);
				ab.setNewUserId("");
				ab.setNewUserPerm("");
				// remove new user from the add users picklist
				otherUsers.remove(upb.getUser());
			}
			ab.setUsers(newUserPerms);
		}

		// ==========================
		// Get User Input.
		// ==========================
		// build the list of available users to add unless
		// we are saving and will not be forwarding to
		// the JSP (and so won't need it.)
		if (!saving) {
			ArrayList addnlUsers = new ArrayList();
			AvailUserBean nullChoice = new AvailUserBean();
			nullChoice.setUser("");
			addnlUsers.add(nullChoice);
			Iterator it = otherUsers.keySet().iterator();
			while (it.hasNext()) {
				String usrName = (String) it.next();
				AvailUserBean aub = new AvailUserBean();
				aub.setUser(usrName);
				addnlUsers.add(aub);
			}
			ab.setAvailableUsers(addnlUsers);

			// the bean is good to go.  we're off to collect input
			return new ActionForward(mapping.getInput());
		}

		// ==================================
		// Apply data to Permission Manager
		//===================================

		// create a new Page Spec (will replace the old one)
		PermissionManager.PageSpec pSpec = pm.new PageSpec();
		
		// pick up user permissions for this page from the bean
		pSpec.userPermLevel = new HashMap();
		Iterator it = ab.getUsers().iterator();
		while (it.hasNext()) {
			UserPermBean upb = (UserPermBean) it.next();
			String permSt = upb.getPerm();
			if(permSt.equals("ADMIN*")) permSt = "ADMIN";
			pSpec.userPermLevel.put(
				upb.getUser(),
				new Integer(pm.permLevelFromString(permSt)));
		}
		// if this administrator needs admin permission to this page
		// (because he is not admin for the parent page) add him to list.
		if (pm
			.userPermLevelForParentPage(pm.getUserName(req), ab.getName())
			< PermissionManager.ADMIN) {
			pSpec.userPermLevel.put(thisAdmin, new Integer(PermissionManager.ADMIN));
		}
		// transfer Max Storage from bean to PageSpec. 
		// Note: this is not user input... it is a hidden field.
		// (arguably this should come from old pSpec if any)
		if (ab.getMaxStorage().length() > 0) {
			try {
				pSpec.maxStorage = Integer.parseInt(ab.getMaxStorage());
			} catch (NumberFormatException e) {
				// TODO flag an error.
			}
		}
		else {
			pSpec.maxStorage = 0;
		}
		// transfer attachment size limit.  (user input)
		if (ab.getMaxSizePerAttachment().length() > 0) {
			try {
				pSpec.maxStoragePerAttach =
					Integer.parseInt(ab.getMaxSizePerAttachment());
			} catch (NumberFormatException e) {
				// TODO flag an error.
			}
		}
		else {
			pSpec.maxStoragePerAttach = -1;
		}
		// transfer reserved storage flag from bean to page spec
		// Note: not user input.  Value is from hidden field.
		String rStSt = ab.getReservedStorage();
		pSpec.reservedStorage = rStSt!=null && rStSt.length()>0;
		
		//transfer the template name
		if(ab.getTemplateName().length()>0) {
			pSpec.templateName = ab.getTemplateName();
		}
		
		// new PageSpec object is good to go.  Install it.
		pm.updatePageSpec(thePage, pSpec);
		
		// now do the administered children
		ArrayList childList = ab.getAdminChildren();
		if(childList!=null) {
			Iterator children = childList.iterator();
			while(children.hasNext()) {
				AdminChildBean acb = (AdminChildBean)children.next();
				// get the child page's PageSpec -- we will update it, not replace it, so we
				// don't need to worry about its user permissions.
				PermissionManager.PageSpec childSpec = pm.getPageSpec(acb.getName());
				if(childSpec!=null) {
					// transfer max storage from bean to page spec
					// this IS user input (for admin children)
					if(acb.getMaxStorage().length()>0) {
						try {
							childSpec.maxStorage = Integer.parseInt(acb.getMaxStorage());
						}
						catch (NumberFormatException e) {
							// TODO - validate to make sure this doesn't happen
						}
					}
					else {
						childSpec.maxStorage = 0;
					}
					// transfer reserved storage flag.
					childSpec.reservedStorage = acb.getReservedStorage()!=null && acb.getReservedStorage().length()>0;
					// transfer max attachment size.
					if(acb.getMaxSizePerAttachment().length()>0) {
						try {
							childSpec.maxStoragePerAttach = Integer.parseInt(acb.getMaxSizePerAttachment());
						}
						catch (NumberFormatException e) {
							// TODO - validate to make sure this doesn't happen
						}
					}
					else {
						childSpec.maxStorage = -1;
					}
					// childSpec has been updated in place.  No need to save.
				}
			}
		}
		
		// tell the permission manager to rewrite the configuration table.
		pm.rewritePageSpecs();
		
		// what to do next?
		if(ab.getGoToChild()!=null && ab.getGoToChild().length()>0) {
			return new ActionForward("/adminPage.do?name="+ab.getGoToChild()+"&resetBean=true");
		}
		if(ab.getGoToParent()!=null && ab.getGoToParent().length()>0) {
			return new ActionForward("/adminPage.do?name="+ab.getAdminParent()+"&resetBean=true");
		}

		// done -- off to view the page.
		return new ActionForward("/viewPage.do?name="+thePage,true);
	}

}
